#include "basic_typedef.h"
#include <iostream>
#include <CGAL/minkowski_sum_2.h>
#include <CGAL/Arrangement_2.h>
#include <CGAL/Gmpz.h>
//#include <CGAL/Gmpq.h>


//#include <CGAL/Polygon_set_2.h>
/* 
	All types are defined in basic_typedef

typedef CGAL::Gmpq                                  Number_type;
typedef CGAL::Cartesian<Number_type>		        Kernel;
typedef Kernel::Point_2								Point;
typedef CGAL::Polygon_2<Kernel>                     Polygon;
typedef CGAL::Polygon_with_holes_2<Kernel>          Polygon_with_holes;
typedef CGAL::Polygon_set_2<Kernel>					Polygon_set;
typedef std::list<Polygon_with_holes>				Polygon_with_holes_container;

*/

using namespace CGAL;
using namespace std;

typedef  Polygon_set::Arrangement_on_surface_2 Arrangement_on_surface;
typedef  Polygon_set::Arrangement_2 Arrangement;

int main(int argc, char* argv[])
{
	/*
		1. Point
		http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Kernel_23_ref/Class_Point_2.html
	*/

	// Create Point with the coordinates (0.5, 0.6)
		Point p(0.5 , 0.6);
	// Now, extract the x and y values into two variables of type Number_type
		Number_type x=p.x() , y=p.y();
	// Use the function CGAL::to_double (or .to_double function of Number_type)
	// to extract the double values of the x and y and print them
		std::cout << "cordinet x of p : " << x.to_double() <<" cordinate y of p : " << y.to_double() <<endl;
	/*
		2. Polygon 
		http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Polygon_ref/Class_Polygon_2.html
	*/

	// Create a polygon from the points (-0.4,0.3) (-1 , 1) (0, 2) (0.7, 0.1)
		Point ps0[]={Point(-0.4,0.3),Point(-1 , 1),Point(0, 2),Point(0.7, 0.1)};
		Polygon poly(ps0,ps0+4) , polyBox;
	// Find the bounding box of the polygon (this is the smallest rectangle [parallel to axes]
	// that contains the polygon) by traversing the points of the polygon using vertices_begin,vertices_end iterators
	// Use procedures that are provided by Number_type (do not work with the double values)
	
		std::cout << *poly.left_vertex() << endl << *poly.right_vertex() << endl << *poly.top_vertex() << endl << *poly.bottom_vertex() << endl;
		polyBox.push_back(*poly.left_vertex());
		polyBox.push_back(*poly.right_vertex());
		polyBox.push_back(*poly.top_vertex());
		polyBox.push_back(*poly.bottom_vertex());
	
	/* 
		3. Polygon_set 
		http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Boolean_set_operations_2_ref/Class_General_polygon_set_2.html
	*/

	
	// Create an empty polygon set (Polygon_set)
	 Polygon_set polySet;
	// Create the polygons A,B,C,D = {(1,1), (2,2), (3,1)}, {(-1,1), (-2,2), (-3,1)},{(-2,1.5), (2,1.5), (2,0), (-2,0)}, 
	//								{(-1,-1),(-2,-2),(2,-2),(1,-1)}
	// and another polygon E = {(-1.8, 4) (1.8,4) (1.8, -4) (-1.8, -4)} 
	// (add the points to the polygons according to the order in which they are written)
	 Point points[]={Point(1,1), Point(2,2), Point(3,1),Point(-1,1), Point(-2,2), Point(-3,1),Point(-2,1.5),Point(2,1.5),
					 Point(2,0),Point(-2,0),Point(-1,-1),Point(-2,-2),Point(2,-2),Point(1,-1)};

	 Point ps[]={Point(-1.8, 4) ,Point(1.8,4) ,Point(1.8, -4) ,Point(-1.8, -4)};
	 Polygon A(points,points+3);
	 Polygon B(points+3,points+6);
	 Polygon C(points+6,points+10);
	 Polygon D(points+10,points+14);
	 Polygon E(ps,ps+3);	
	// In order to use the polygon_set the polygons must be counter-clockwise oriented
	 // check counterclockwise orientation
	if (A.orientation() == CGAL::CLOCKWISE) 
	{
		A.reverse_orientation();
	}
	if (B.orientation() == CGAL::CLOCKWISE) 
	{
		B.reverse_orientation();
	}if (C.orientation() == CGAL::CLOCKWISE) 
	{
		C.reverse_orientation();
	}if (D.orientation() == CGAL::CLOCKWISE) 
	{
		D.reverse_orientation();
	}if (E.orientation() == CGAL::CLOCKWISE) 
	{
		E.reverse_orientation();
	}
	// For every polygon A,B,C,D,E check that it is counter-clockwise using the "is_counterclockwise_oriented()" predicate
	// In case it's not, use "reverse_orientation()"

	// Insert A,B,C,D into a polygon set called UNION using the "join" operation ("insert" can be used only if the polygons are disjoint)
	// Find the intersection of E with UNION set using the "intersection" operation of the polygon_set
	// Denote this intersection by INTER
	Polygon polyGroup[] = {A,B,C,D};
	Polygon_set UNION , INTER;
	UNION.join(polyGroup,polyGroup+4);

	INTER = UNION;
	INTER.intersection(E);


	// Determine whether each of the points (1.5,2.6),(1.9,0.09) is located inside UNION (using oriented_side)
	if( UNION.oriented_side(Point(1.5,2.6)) == CGAL::Sign::ON_ORIENTED_BOUNDARY)
	{
		std::cout << "the point : (1.5,2.6) is on inside UNION" << endl;
	}
	if( UNION.oriented_side(Point(1.9,0.09)) == CGAL::Sign::ON_ORIENTED_BOUNDARY)
	{
		std::cout << "the point : (1.9,0.09) is on inside UNION" << endl;
	}
	/*
		4. Polygon_with_holes
		http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Boolean_set_operations_2_ref/Concept_GeneralPolygonWithHoles_2.html#Cross_link_anchor_1005
	*/

	// The result INTER is represented as a collection of Polygon_with_holes
	// Extract all the Polygon_with_holes that define INTER and for each polygon 
	// Print the vertices that define its boundary

	/*	
		hint:
		Polygon_set ps; 
		Polygon_with_holes_container container; 
		ps.polygons_with_holes (std::back_inserter (container));
	*/ 
		int i=1;
		Polygon_with_holes_container poly_list; 
		INTER.polygons_with_holes (std::back_inserter (poly_list));
		for (Polygon_with_holes_container::iterator pit = poly_list.begin(); pit != poly_list.end(); ++pit,i++){
			Polygon_with_holes P = *pit;
			cout << "Polygon: " << i << endl;
			Polygon O = P.outer_boundary();
			for (Polygon::Vertex_const_iterator vit = O.vertices_begin(); vit != O.vertices_end(); ++vit){
				cout << " (" << *vit << ")";
			}
			cout << endl;
			

		}

	/*
		5. Arrangement
		http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Arrangement_on_surface_2_ref/Class_Arrangement_2.html#Cross_link_anchor_1186
	*/
		 //#include <CGAL/Arrangement_2.h>
	//	Extract the underlying arrangement of the INTER polygon set
		Arrangement arr = INTER.arrangement();
	//	Traverse the faces of the arrangement and print the vertices of each face
		 Arrangement::Face_iterator fit;

		 for (fit = arr.faces_begin();fit!=arr.faces_end();++fit)
			
		 {//TODO need to check how to print vertices and so on
			 
			 Arrangement::Face f = *fit;
			 //Arrangement::Ccb_halfedge_circulator curr = f.outer_ccb();

			 for (Arrangement::Outer_ccb_iterator oit=f.outer_ccbs_begin();oit!=f.outer_ccbs_end();++oit){
				 Arrangement::Ccb_halfedge_circulator curr = *oit;
				 Arrangement::Ccb_halfedge_circulator first = curr;
		
			  Arrangement::Halfedge h;
			 
			 do{

				 Arrangement::Halfedge h = *curr;
				 Arrangement::Vertex  v = *h.source();
				 cout << "*****("<<v.point().x() << ","<<v.point().y() <<")"<< endl;
				 v = *h.target();
				 cout << "*****("<<v.point().x() << ","<<v.point().y() <<")"<< endl;

			 }while (curr != first);
			 }
	
			 

			 for (Arrangement::Inner_ccb_iterator iit=f.inner_ccbs_begin();iit!=f.inner_ccbs_end();++iit){
				 Arrangement::Ccb_halfedge_circulator curr = *iit;
				 Arrangement::Ccb_halfedge_circulator first = curr;
		
			  Arrangement::Halfedge h;
			 
			 do{

				 Arrangement::Halfedge h = *curr;
				 Arrangement::Vertex  v = *h.source();
				 cout << "#####("<<v.point().x() << ","<<v.point().y() <<")"<< endl;
				 v = *h.target();
				 cout << "#####("<<v.point().x() << ","<<v.point().y() <<")"<< endl;

			 }while (curr != first);
			 }
			 	 

		 }



	/*
		6. Minkowski Sums and Arrangements 
		http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Minkowski_sum_2/Chapter_main.html
	*/
	//	Generate the polygons	P = {(0,0)(-2,0)(-3,-1)(-3,-4),(-2,-5)(3,-5)(4,-4)(4,-1)(3,0)(1,0)(1,-1),
	//								(3,-1)(3,-4)(-2,-4)(-2,-1)(0,-1)}
	//							Q = {(1,1)(1,0)(0,0)(0,1)}
	 Point points1[] ={Point(0,0),Point(-2,0),Point(-3,-1),Point(-3,-4),Point(-2,-5),Point(3,-5),Point(4,-4),Point(4,-1),Point(3,0),Point(1,0),Point(1,-1),Point(3,-1),Point(3,-4),Point(-2,-4),Point(-2,-1),Point(0,-1)};
	 Point ps1[]={Point(1,1),Point(1,0),Point(0,0),Point(0,1)};
	 Polygon P(points1,points1+14);
	 Polygon Q(ps1,ps1+4);

	 //TODO --- #include <CGAL/minkowski_sum_2.h>
	//	Find the Minkowski sums of P and Q

	//	Denote the result by MINK
		 Polygon_with_holes  MINK = minkowski_sum_2 (P, Q);

	//	Print the faces of MINK and its complement

		 
		 Polygon_with_holes_container COMP; 
		 
		 complement(MINK,std::back_inserter (COMP));


		 Polygon::Vertex_iterator vit;

		 print_polygon_with_holes(MINK);
	
		/*for (vit = BOUND.vertices_begin(); vit!=BOUND.vertices_begin();++vit){
			
			std::cout << "x : " << vit->x().to_double() <<" y : " << vit->y().to_double() <<endl;
		}*/

		 Polygon_with_holes PH;
		for (Polygon_with_holes_container::iterator it2 = COMP.begin(); it2 != COMP.end(); ++it2){
			
			PH = *it2;

			print_polygon_with_holes(PH);
		}

	return 0;
}

 
